﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Xml.Linq;
using Microsoft.SharePoint;
using System.Text.RegularExpressions;

namespace LizardSoft.Common.FlexibleStructureDeployment
{
    public static partial class StructureHelper
    {
        private static void AddNewFields(SPWeb web, string listFolderUrl, SPContentTypeId listContentTypeId, SPContentType siteContentType)
        {
            SPList list = GetSPListFromFolderUrl(web, listFolderUrl);
            SPContentType listContentType = list.ContentTypes[listContentTypeId];
            SPFieldCollection listContentTypeFields = listContentType.Fields;

            // получаем набор названий полей, которые нужно добавить
            List<string> fieldsToBeAddedNames = new List<string>();
            foreach (SPFieldLink siteContentTypeFieldLink in siteContentType.FieldLinks)
            {
                if (!listContentTypeFields.Contains(siteContentTypeFieldLink.Id))
                {
                    // в типе контента списка поле еще отсутствует
                    fieldsToBeAddedNames.Add(siteContentTypeFieldLink.Name);
                }
            }

            // если первичное поле добавляется вместе с зависимыми, то необходимо отсортировать поля так,
            // чтобы сначала были добавлены все первичные поля, а только потом - зависимые
            SPWeb rootWeb = web.Site.RootWeb;
            SPFieldCollection siteFields = rootWeb.Fields;
            List<FieldDependancyInfo> fieldsToBeAdded = new List<FieldDependancyInfo>();
            foreach (string fieldToBeAddedName in fieldsToBeAddedNames)
            {
                SPField fieldToBeAdded = siteFields.GetFieldByInternalName(fieldToBeAddedName);
                FieldDependancyInfo dependancyInfo = new FieldDependancyInfo();
                dependancyInfo.Field = fieldToBeAdded;
                if (fieldToBeAdded is SPFieldCalculated) // вычисляемый столбец всегда зависит от других столбцов
                {
                    dependancyInfo.IsDependent = true;
                }
                else if (fieldToBeAdded is SPFieldLookup)
                {
                    dependancyInfo.IsDependent = ((SPFieldLookup)fieldToBeAdded).IsDependentLookup;
                }
                fieldsToBeAdded.Add(dependancyInfo);
            }
            // поместим все зависимые поля в конец
            fieldsToBeAdded = fieldsToBeAdded.OrderByDescending(x => x, new FieldDependancyInfoComparer()).ToList();

            // добавляем поля
            foreach (FieldDependancyInfo fieldToBeAdded in fieldsToBeAdded)
            {
                try
                {
                    SPFieldCollection listFields = list.Fields;
                    if (!listFields.Contains(fieldToBeAdded.Field.Id))
                    {
                        listFields.Add(fieldToBeAdded.Field);
                        list.Update();
                        list = GetSPListFromFolderUrl(web, listFolderUrl); // переоткрываем список
                        listContentType = list.ContentTypes[listContentTypeId]; // переоткрываем тип контента
                    }
                    SPFieldLinkCollection listContentTypeFieldLinks = listContentType.FieldLinks;
                    if (listContentTypeFieldLinks[fieldToBeAdded.Field.Id] == null)
                    {
                        // надо добавить недостающий FieldLink
                        listContentTypeFieldLinks.Add(new SPFieldLink(fieldToBeAdded.Field));
                    }
                    else
                    {
                        int doublCount = 0;
                        foreach (SPFieldLink checkFieldLink in listContentTypeFieldLinks)
                        {
                            if (checkFieldLink.Id == fieldToBeAdded.Field.Id) doublCount++;
                        }
                        if (doublCount == 2)
                        {
                            // надо удалить лишний FieldLink
                            listContentTypeFieldLinks.Delete(fieldToBeAdded.Field.Id);
                        }
                    }
                    listContentType.Update();
                    listContentType = list.ContentTypes[listContentTypeId]; // переоткрываем тип контента
                }
                catch (Exception ex)
                {
                    string message = String.Format(
                        "Ошибка в методе AddNewFields для списка {0}, типа контента {1} и поля {2}: {3}",
                        listFolderUrl,
                        listContentType.Name,
                        fieldToBeAdded.Field.InternalName,
                        ex.Message);
                    throw new Exception(message, ex);
                }
            }
        }
    }
}
